package com.qd.panda.mq.park;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.DateUtil;
import com.cdqidi.util.SpringContextHolder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qd.common.panda.constant.PandaConstant;
import com.qd.common.panda.domain.entity.stroke.UserStrokeDTO;
import com.qd.common.sys.domain.entity.log.ReceiveLogDTO;
import com.qd.common.sys.event.ReceiveLogEvent;
import com.qd.panda.model.UserPlateRelation;
import com.qd.panda.mq.bo.ParkBO;
import com.qd.panda.service.park.CarParkService;
import com.qd.panda.service.plate.UserPlateRelationService;
import com.qd.panda.service.stroke.DisplayUtil;
import com.qd.panda.service.stroke.UserStrokeHolderService;
import com.qd.panda.service.stroke.UserStrokeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Optional;

/**
 * @author sjk
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class ParkConsumerService {
    private final CarParkService carParkService;
    private final UserStrokeService userStrokeService;
    private final ObjectMapper objectMapper;
    private final UserStrokeHolderService userStrokeHolderService;
//    private final PlateService plateService;
    private final UserPlateRelationService userPlateRelationService;

    @Transactional(rollbackFor = Exception.class)
    public void doProcess(String json) {
        if(log.isDebugEnabled()) {
            log.debug("进出场消息: {}", json);
        }
        LocalDateTime now = LocalDateTime.now();
        ReceiveLogDTO receiveLog = new ReceiveLogDTO();
        receiveLog.setContent(json);
        receiveLog.setAddTime(now);
        String errMsg = null;
        try {
            try {
                final ParkBO parkBO = objectMapper.readValue(json, ParkBO.class);
                checkParams(parkBO);
                if (Optional.ofNullable(carParkService.getById(parkBO.getParkingId())).isEmpty()) {
                    throw new ApiException("停车场不存在");
                }
                final UserStrokeDTO userStrokeDTO = getUserStroke(parkBO);
                if (parkBO.getType().equals(ParkBO.IN)) {
                    in(userStrokeDTO, parkBO);
                } else {
                    out(userStrokeDTO, parkBO);
                }
                parkBO.freeData();
                userStrokeDTO.freeData();
            } catch (Exception e) {
                errMsg = e.getMessage();
            }
        } finally {
            //记录日志
            if (null != errMsg) {
                receiveLog.setErrMsg(errMsg);
            }
            receiveLog.setLogType(PandaConstant.LOG_TYPE_PARK_OUT);
            SpringContextHolder.publishEvent(new ReceiveLogEvent(receiveLog));
        }
    }

//    /**
//     * 更新车牌号是否支持ETC支付
//     *
//     * @param parkBO 车牌号和是否支持ETC支付
//     */
//    private void updatePlate(ParkBO parkBO) {
//        final Plate plate = plateService.getById(parkBO.getPlateNumber());
//        if (null != plate) {
//            String etcPay = parkBO.getEtc().equals(1) ? ConstantDto.SF1 : ConstantDto.SF0;
//            if (!plate.getEtcPay().equals(etcPay)) {
//                plate.setEtcPay(etcPay);
//                plateService.clearCache(plate);
//                plateService.updateById(plate);
//            }
//            plate.freeData();
//        }
//    }

    /**
     * 获得行程记录，为空的话直接报错
     *
     * @param parkBO mq
     * @return 行程
     */
    private UserStrokeDTO getUserStroke(ParkBO parkBO) {
        UserStrokeDTO userStrokeDTO = userStrokeService.getBaseMapper().getUserStrokeByParkIdAndPlateNumber(parkBO.getParkingId(), parkBO.getPlateNumber());
        if (null == userStrokeDTO) {
            final UserPlateRelation userPlateRelation = userPlateRelationService.getUniqueByPlateNumber(parkBO.getPlateNumber());
            if (null != userPlateRelation) {
                userStrokeDTO = userStrokeHolderService.createUserStroke(IdWorker.getIdStr(), parkBO.getParkingId(), parkBO.getPlateNumber(), DisplayUtil.TRIP_TYPE_0, null, userPlateRelation.getUserId(), BigDecimal.valueOf(0D));
            }
        } else {
            if (userStrokeDTO.getTripType().equals(DisplayUtil.TRIP_STATUS_2)) {
                throw new ApiException("行程已经结束不处理");
            }
        }
        return userStrokeDTO;
    }

    /**
     * 出场
     *
     * @param userStrokeDTO 行程
     * @param parkBO        mq消息对象
     */
    private void out(UserStrokeDTO userStrokeDTO, ParkBO parkBO) {
        //出的
        if (userStrokeDTO.getProcessStatus().equals(DisplayUtil.PROCESS_STATUS_4)) {
            //只处理已缴费未出场的
            final String outTime = parkBO.getOutTime();
            LocalDateTime outTimeLocalDateTime;
            if (StringUtils.hasLength(outTime)) {
                try {
                    outTimeLocalDateTime = DateUtil.strToLocalDateTime(outTime);
                } catch (Exception e) {
                    log.error("日期转换失败,outTime: {}", parkBO.getOutTime());
                    throw e;
                }
            } else {
                outTimeLocalDateTime = LocalDateTime.now();
            }
            userStrokeDTO.setOutTime(outTimeLocalDateTime);
            userStrokeDTO.setTripStatus(DisplayUtil.TRIP_STATUS_2);
            userStrokeHolderService.outPark(outTimeLocalDateTime, userStrokeDTO, "");
            userStrokeHolderService.buildParkNum(userStrokeDTO.getSid(), userStrokeDTO.getParkId());
        } else {
            log.error("出场只处理已缴费未出场的，当前processStatus: {}", userStrokeDTO.getProcessStatus());
        }
    }

    /**
     * 入场
     *
     * @param userStrokeDTO 行程
     * @param parkBO        p
     */
    private void in(UserStrokeDTO userStrokeDTO, ParkBO parkBO) {
        if (userStrokeDTO.getProcessStatus().equals(DisplayUtil.PROCESS_STATUS_0)) {
            //只处理交了预约费但是还没有入场的
            LocalDateTime inTime = DateUtil.strToLocalDateTime(parkBO.getInTime());
            userStrokeDTO.setStartTime(inTime);
            userStrokeDTO.setIntoTime(inTime);
            userStrokeDTO.setBillStartTime(inTime);
            userStrokeDTO.setProcessStatus(DisplayUtil.PROCESS_STATUS_3);
            if (Boolean.TRUE.equals(userStrokeService.isExistsById(userStrokeDTO.getSid()))) {
                userStrokeService.update(userStrokeDTO);
            } else {
                userStrokeService.save(userStrokeDTO);
            }
            userStrokeDTO.freeData();
        } else {
            throw new ApiException("入场只处理0的，当前processStatus: " + userStrokeDTO.getProcessStatus());
        }
    }

    private void checkParams(ParkBO parkBO) {
        final String type = parkBO.getType();
        if (!StringUtils.hasLength(type)) {
            throw new ApiException("进出方向为空");
        }
        if (!StringUtils.hasLength(parkBO.getParkingId())) {
            throw new ApiException("停车场ID为空");
        }
        if (!StringUtils.hasLength(parkBO.getPlateNumber())) {
            throw new ApiException("车牌号为空");
        }
        if (type.equals(ParkBO.IN)) {
            if (!StringUtils.hasLength(parkBO.getInTime())) {
                throw new ApiException("type为in的时候，inTime为空");
            }
        } else if (type.equals(ParkBO.OUT)) {
            if (!StringUtils.hasLength(parkBO.getOutTime())) {
                throw new ApiException("type为out的时候，outTime为空");
            }
        } else {
            throw new ApiException("type类型错误");
        }
    }
}